`timescale 1ns/1ps
`default_nettype none
module cpu_top #(
    parameter IMEM_DEPTH = 256   // 指令存储深度（按字）
)(
    input  wire clk,   // 时钟：所有时序单元在上升沿工作
    input  wire rstn   // 同步复位（低有效）：拉低一个或多个时钟上升沿生效
);

    // =========================================================================
    // IF 取指阶段
    //   - pc 仅做：复位到 0，每拍 +4
    //   - imem 按字对齐读取指令（addr[31:2] 作为字地址）
    //   - if_id_reg 打拍 pc 与 instr，进入 ID 阶段
    // =========================================================================
    wire [31:0] pc_q;        // 当前取指地址（字节地址）
    wire [31:0] instr_if;    // 从指令存储取出的指令字

    pc u_pc(
        .clk (clk),
        .rstn(rstn),
        .pc_q(pc_q)
    );

    // 说明：imem 内部不做 $readmemh，便于 tb 层统一加载（层次路径：dut.u_imem.mem）
    imem #(
        .DEPTH_WORDS(IMEM_DEPTH)
    ) u_imem (
        .addr (pc_q),
        .instr(instr_if)
    );

    // IF/ID 级间寄存器：把 pc 与 instr 打拍给 ID
    wire [31:0] id_pc;
    wire [31:0] id_instr;
    if_id_reg u_ifid(
        .clk     (clk),
        .rstn    (rstn),
        .if_pc   (pc_q),
        .if_instr(instr_if),
        .id_pc   (id_pc),
        .id_instr(id_instr)
    );

    // =========================================================================
    // ID 译码/读寄存器阶段
    //   - controller：根据 opcode/funct3/funct7 组合译码出：regwrite / alusrc / alu_ctrl
    //   - regfile   ：组合读 rs1, rs2；同步写（x0 恒 0）
    //   - imm_gen   ：生成 I 型有符号扩展立即数
    //   - id_ex_reg ：将 rs1、rs2、imm 及控制信号打拍到 EX
    // =========================================================================
    // RISC-V 位段（供直连与注释理解；控制器内部也会拆解）
    wire [4:0] rs1 = id_instr[19:15];
    wire [4:0] rs2 = id_instr[24:20];
    wire [4:0] rd  = id_instr[11:7];

    // controller：当前仅输出三条信号
    wire        c_regwrite;  // 本指令最终是否需要写回寄存器堆
    wire        c_alusrc;    // 1=ALU 的 B 源取 imm（I 型），0=取 rs2（R 型）
    wire [3:0]  c_alu_ctrl;  // 0000=ADD，0001=SUB（与 alu.v 对齐）
    wire        c_memread;
    wire        c_memwrite;
    wire        c_memtoreg;

    controller u_ctrl(
        .instr    (id_instr),
        .regwrite (c_regwrite),
        .alusrc   (c_alusrc),
        .alu_ctrl (c_alu_ctrl),
        .memread(c_memread), 
        .memwrite(c_memwrite), 
        .memtoreg(c_memtoreg)
    );

    // 寄存器堆：组合读（rdata1/rdata2），同步写（在 WB 阶段完成）
    wire [31:0] rdata1;
    wire [31:0] rdata2;

    //为支持访存指令增加
    // WB：最终写回数据（供 regfile & 前递单元）
    wire [31:0] wb_wdata = wb_memtoreg ? wb_rdata : wb_alu_y;

    regfile u_rf(
        .clk   (clk),
        .rstn  (rstn),
        .we    (wb_regwrite),   // 来自 MEM/WB 的写回使能
        .rs1   (rs1),
        .rs2   (rs2),
        .rd    (wb_rd),         // 回写目的寄存器
        .wdata (wb_wdata),      // 回写数据（最小版：恒为 ALU 结果）
        .rdata1(rdata1),
        .rdata2(rdata2)
    );

    // 立即数生成：仅 I 型用到（ADDI）
    wire [31:0] imm_i,imm_s;
    imm_gen u_imm(
        .instr(id_instr),
        .imm_i(imm_i), 
        .imm_s(imm_s)
    );
    wire [31:0] id_imm_sel = c_memwrite ? imm_s : imm_i; // SW 用 S 立即数，其余用 I


    // ID/EX 级间寄存器：把 ID 阶段的数据与控制信号打拍给 EX
    wire [31:0] ex_rdata1;
    wire [31:0] ex_rdata2;
    wire [31:0] ex_imm;
    wire [4:0]  ex_rs1, ex_rs2, ex_rd; // ★ 新增 增加 exrs1 和 exrs2解决数据冒险
    wire        ex_regwrite;
    wire        ex_alusrc;
    wire [3:0]  ex_alu_ctrl;

    //为mem存阶段增加
    wire        ex_memread, ex_memwrite, ex_memtoreg;

    id_ex_reg u_idex(
        .clk        (clk),
        .rstn       (rstn),
        .id_rdata1  (rdata1),
        .id_rdata2  (rdata2),
        .id_imm     (id_imm_sel),
        .id_rs1     (rs1),                 // ★ 新增 解决数据冒险
        .id_rs2     (rs2),                 // ★ 新增 解决数据冒险
        .id_rd      (rd),
        .id_regwrite(c_regwrite),
        .id_alusrc  (c_alusrc),
        .id_alu_ctrl(c_alu_ctrl),
        .id_memread(c_memread),           // ★ 新增 为访存
        .id_memwrite(c_memwrite),         // ★ 新增 为访存
        .id_memtoreg(c_memtoreg),         // ★ 新增 为访存
        .ex_rdata1  (ex_rdata1),
        .ex_rdata2  (ex_rdata2),
        .ex_imm     (ex_imm),
        .ex_rs1     (ex_rs1),           // ★ 新增 解决数据冒险
        .ex_rs2     (ex_rs2),           // ★ 新增 解决数据冒险
        .ex_rd      (ex_rd),
        .ex_regwrite(ex_regwrite),
        .ex_alusrc  (ex_alusrc),
        .ex_alu_ctrl(ex_alu_ctrl),
        .ex_memread(ex_memread),          // ★ 新增 为访存
        .ex_memwrite(ex_memwrite),        // ★ 新增 为访存
        .ex_memtoreg(ex_memtoreg)         // ★ 新增 为访存
  
    );

    // =========================================================================
    // EX 执行阶段
    //   - 选择 ALU 的 B 源：I 型 -> imm；R 型 -> rs2
    //   - ALU 根据 alu_ctrl 执行加/减；结果进入 EX/MEM
    // =========================================================================
    // 前递控制：比较 EX 源 vs EX/MEM & MEM/WB 的写回目的
    wire [1:0] fwd_a_sel, fwd_b_sel;
    forwarding_unit u_fwd(
        .ex_rs1(ex_rs1), 
        .ex_rs2(ex_rs2),
        .mem_regwrite(mem_regwrite), 
        .mem_rd(mem_rd),
        .wb_regwrite(wb_regwrite),   
        .wb_rd(wb_rd),
        .fwd_a_sel(fwd_a_sel), 
        .fwd_b_sel(fwd_b_sel)
    );

    // 选择 A 端
    wire [31:0] alu_a_pre =
        (fwd_a_sel == 2'b10) ? mem_alu_y :
        (fwd_a_sel == 2'b01) ? wb_wdata  :    // ★ WB 最终写回值
                                ex_rdata1 ;

    // 选择 B 端（先做前递，再根据 ex_alusrc 决定是否取 imm）
    wire [31:0] rdata2_fwd =
        (fwd_b_sel == 2'b10) ? mem_alu_y :
        (fwd_b_sel == 2'b01) ? wb_wdata  :   // ★
                                ex_rdata2 ;
    wire [31:0] alu_b = ex_alusrc ? ex_imm : rdata2_fwd;

    wire [31:0] alu_y;                                  // ALU 运算结果
    alu u_alu(
        .a        (alu_a_pre),
        .b        (alu_b),
        .alu_ctrl (ex_alu_ctrl),  // 0000=ADD, 0001=SUB
        .y        (alu_y)
    );

    // EX/MEM 级间寄存器：把 ALU 结果与写回元信息打拍给 MEM
    wire [31:0] mem_alu_y,mem_wdata;  // ★为访存指令增加mem_wdata
    wire [4:0]  mem_rd;
    wire        mem_regwrite;

    //为访存指令增加
    wire        mem_memread, mem_memwrite, mem_memtoreg;

    ex_mem_reg u_exmem(
        .clk        (clk),
        .rstn       (rstn),
        .ex_alu_y(alu_y), 
        .ex_wdata(rdata2_fwd),      // ★ SW 的写数据使用前递后的 rs2
        .ex_rd      (ex_rd),
        .ex_regwrite(ex_regwrite),
        .ex_memread(ex_memread),        // ★为访存指令增加
        .ex_memwrite(ex_memwrite),      // ★为访存指令增加
        .ex_memtoreg(ex_memtoreg),      // ★为访存指令增加
        .mem_alu_y  (mem_alu_y),
        .mem_wdata(mem_wdata),
        .mem_rd     (mem_rd),
        .mem_regwrite(mem_regwrite),
        .mem_memread(mem_memread),      // ★为访存指令增加
        .mem_memwrite(mem_memwrite),    // ★为访存指令增加
        .mem_memtoreg(mem_memtoreg)     // ★为访存指令增加
  
    );

    // =========================================================================
    // MEM 访存阶段
    // =========================================================================
    wire [31:0] mem_rdata;
    dmem u_dmem(
        .clk(clk),
        .memread(mem_memread),
        .memwrite(mem_memwrite),
        .addr(mem_alu_y),
        .wdata(mem_wdata),
        .rdata(mem_rdata)
    );

    // =========================================================================
    // WB 回写阶段
    // =========================================================================
    wire [31:0] wb_alu_y, wb_rdata;  
    wire [4:0]  wb_rd;
    wire        wb_regwrite, wb_memtoreg;

    // MEM/WB 级间寄存器：把写回相关信息从 MEM 打拍到 WB
    mem_wb_reg u_memwb(
        .clk         (clk),
        .rstn        (rstn),
        .mem_alu_y   (mem_alu_y),
        .mem_rdata(mem_rdata),          // ★为访存指令增加
        .mem_rd      (mem_rd),
        .mem_regwrite(mem_regwrite),
        .mem_memtoreg(mem_memtoreg),    // ★为访存指令增加
        .wb_alu_y    (wb_alu_y),
        .wb_rdata(wb_rdata),            // ★为访存指令增加
        .wb_rd       (wb_rd),
        .wb_regwrite (wb_regwrite),
        .wb_memtoreg(wb_memtoreg)       // ★为访存指令增加
    );
endmodule